/* NOTICE
 
    Jim - the Java Image Manager, copyright (c) 2005 - 2007 Grant Gardner 
 
    Jim is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Jim is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  
    In addition, as a special exception, you are permitted to link this code
    with the 3rd party libraries required to compile this file and to
    distribute a linked combination including them. You must obey the
    GNU General Public License in all respects for all of the code except for
    those 3rd party libraries that are licenced under terms incompatible with the
    GNU General Public License.  
 
 
 NOTICE */

package au.com.lastweekend.jim.controller;

import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JList;
import javax.swing.JTree;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import org.apache.log4j.Logger;

import au.com.lastweekend.jim.imagebase.ImageBase;
import au.com.lastweekend.jim.model.ContactSheetListItem;
import au.com.lastweekend.jim.model.Keyword;
import au.com.lastweekend.jim.model.KeywordTreeModel;
import au.com.lastweekend.jim.swing.tree.TreeSelectionController;
import au.com.lastweekend.jim.util.TriState;
import au.com.lastweekend.jim.view.ContactSheet;

/**
 * 
 * ListSelectionListener for each contact sheet to display a tri-state selection for keywords from the selected items.
 * 
 * Maintain allSelected and someSelected sets. Everything else is not selected.
 * 
 * allSelected is the intersection and someselection is union of each of the keyword sets from the selected items. On selection
 * change, deleselect everything from someSelected, recreate allSelected and someSelected. For everything in someSelected set the
 * keyword to TriState.UNKNOWN For everything in allSelected set the keyword to TriState.SELECTED
 * 
 * @author ggardner
 * 
 */
public class KeywordMetadataSelectionController extends TreeSelectionController implements ListSelectionListener {

    private static final Logger LOG = Logger.getLogger(KeywordMetadataSelectionController.class);
    private JTree keywordTree;
    private Set<String> someSelected = new HashSet<String>();
    private Set<String> allSelected = new HashSet<String>();
    private boolean allImported = false;
    private Object[] selectedValues = new Object[0];

    /**
     * @param keywordMetadataTree
     * @param jimController
     */
    public KeywordMetadataSelectionController(JTree keywordTree) {

        this.keywordTree = keywordTree;
        bindTo(keywordTree);

    }

    @Override
    protected void toggleSelection(TreeModel model, TreePath selectionPath) {

        Keyword keyword = (Keyword) selectionPath.getLastPathComponent();
        if (keyword == null || keyword.isNew() || keyword.isRoot()) {
            LOG.debug("Ignoring invalid keyword for selection " + keyword);
            return;
        }

        if (!allImported) {
            LOG.debug("Not all selected items are imported, ignoring toggle selection");
            return;
        }

        keyword.setSelectedState(keyword.getSelectedState().nextUserState());
        TriState newState = keyword.getSelectedState();
        for (Object selectedObject : selectedValues) {
            ContactSheetListItem selectedItem = (ContactSheetListItem) selectedObject;
            selectedItem.updateKeywordSelection(KeywordTreeModel.getImageBaseString(keyword), newState.isSelected());
        }

        ((KeywordTreeModel) keywordTree.getModel()).nodeChanged(keyword);

    }

    public void valueChanged(ListSelectionEvent e) {

        JList list = (JList) e.getSource();
        if (list.getValueIsAdjusting()) {
            // do nothing
            return;
        }
        selectedValues = list.getSelectedValues();

        someSelected.clear();
        allSelected.clear();

        boolean first = true;
        // if nothing is selected the tree cannot be maintained
        allImported = (selectedValues.length > 0);
        for (Object selectedValue : selectedValues) {

            ContactSheetListItem selectedItem = (ContactSheetListItem) selectedValue;

            if (!selectedItem.isImported()) {
                allImported = false;
            }
            Set<String> itemKeywords = selectedItem.getAllKeywords();
            if (first) {
                allSelected.addAll(itemKeywords);
                first = false;
            } else {
                allSelected.retainAll(itemKeywords);
            }
            someSelected.addAll(itemKeywords);
        }

        // Run through the keyword tree, resetting the selections.
        Keyword root = (Keyword) keywordTree.getModel().getRoot();
        setSelectedStates(root, "");

        ((KeywordTreeModel) keywordTree.getModel()).nodeChanged(root);
    }

    /**
     * @param keyword
     * @param keywordString
     */
    private void setSelectedStates(Keyword keyword, String keywordString) {

        if (someSelected.contains(keywordString)) {
            if (allSelected.contains(keywordString)) {
                keyword.setSelectedState(TriState.SELECTED);
            } else {
                keyword.setSelectedState(TriState.UNKNOWN);
            }
        } else {
            keyword.setSelectedState(TriState.NOT_SELECTED);
        }
        keyword.setKeywordsEnabled(allImported);

        Enumeration<Keyword> children = keyword.children();
        while (children.hasMoreElements()) {
            Keyword child = children.nextElement();

            String childKeywordString = (keywordString.length() > 0) ? keywordString + ImageBase.KEYWORD_SEPARATOR_CHAR
                    + child.getName() : child.getName();
            setSelectedStates(child, childKeywordString);
        }

    }

    public void addTo(ContactSheet newSheet) {

        newSheet.getViewList().addListSelectionListener(this);

    }
}
